package com.stox.ui.javafx.charting.draw.shape;

import java.util.Date;
import java.util.List;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

import com.stox.dto.AbstractBar;
import com.stox.ui.javafx.charting.model.uiunit.AbstractPrimaryUiUnit;
import com.stox.ui.javafx.charting.model.uiunit.AbstractUiUnit;
import com.stox.ui.javafx.charting.widget.ResizableCanvas;

public class ControlPoint extends AbstractShape{

	private boolean listenersActivated = true;
	
	private DoubleProperty price;
	public DoubleProperty priceProperty(){
		if(null == price){
			price = new SimpleDoubleProperty(this, "price", 0);
		}
		return price;
	}
	public double getPrice(){
		return null == price ? 0 : price.get();
	}
	public void setPrice(double price){
		priceProperty().set(price);
	}

	private LongProperty date;
	public LongProperty dateProperty(){
		if(null == date){
			date = new SimpleLongProperty(this, "date");
		}
		return date;
	}
	public Date getDate(){
		return null == date ? null : new Date(date.get());
	}
	public Long getDateAsLong(){
		return null == date ? null : date.get();
	}
	public void setDate(Date date){
		dateProperty().set(null == date ? null : date.getTime());
	}
	
	private DoubleProperty x;
	public DoubleProperty xProperty(){
		if(null == x){
			x = new SimpleDoubleProperty(this, "x");
		}
		return x;
	}
	public double getX(){
		return null == x ? 0 : x.get();
	}
	public void setX(double x){
		xProperty().set(x);
	}
	
	private DoubleProperty y;
	public DoubleProperty yProperty(){
		if(null == y){
			y = new SimpleDoubleProperty(this, "y");
		}
		return y;
	}
	public double getY(){
		return null == y ? 0 : y.get();
	}
	public void setY(double y){
		yProperty().set(y);
	}
	
	public ControlPoint(ResizableCanvas canvas) {
		super(canvas);
		xProperty().addListener(new ChangeListener<Number>(){
			@Override
			public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number newValue) {
				if(listenersActivated){
					List<AbstractUiUnit> uiUnits = canvas.getChart().getFrontPlot().getUiUnits();
					for(AbstractUiUnit uiUnit : uiUnits){
						if(uiUnit.getX() <= getX() && uiUnit.getX() + uiUnit.getWidth() >= getX()){
							// TODO - Proper use of generics and inheritence hiararchy to avoid this
							AbstractBar abstractBar = (AbstractBar)uiUnit.getModel();
							setDate(abstractBar.getDate());
						}
					}
				}
			}
		});
		
		yProperty().addListener(new ChangeListener<Number>(){
			@Override
			public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number newValue) {
				if(listenersActivated){
					// TODO - Proper use of generics and inheritence hiararchy to avoid this
					List<AbstractUiUnit> uiUnits = canvas.getChart().getFrontPlot().getUiUnits();
					setPrice(uiUnits.get(0).price(getY()));
				}
			}
		});
	}
	
	public void update(){
		try{
			listenersActivated = false;
			// TODO - Proper use of generics and inheritence hiararchy to avoid this
			List<AbstractPrimaryUiUnit> uiUnits = getCanvas().getChart().getFrontPlot().getUiUnits();
			if(null == uiUnits || uiUnits.isEmpty())
				return;
			
			setY(uiUnits.get(0).height(getPrice()));
			
			if(null != getDate()){
				Date date = getDate();
				setX(-1);
				for(int index = getCanvas().getChart().getChartingView().getStartIndex(); index < getCanvas().getChart().getChartingView().getEndIndex() - 1; index++){
					AbstractPrimaryUiUnit currentUiUnit = uiUnits.get(index);
					AbstractPrimaryUiUnit previousUiUnit = uiUnits.get(index + 1);
					if(null != currentUiUnit && null != previousUiUnit){
						AbstractBar currentBar = (AbstractBar)currentUiUnit.getModel();
						AbstractBar previousBar = (AbstractBar)previousUiUnit.getModel();
						if(date.equals(currentBar.getDate()) || (date.before(currentBar.getDate()) && date.after(previousBar.getDate()))){
							setX(currentUiUnit.getX() + currentUiUnit.getWidth()/2);
						}
					}
				}
			}
		}finally{
			listenersActivated = true;
		}
	}
	
	@Override
	public void paint() {
		GraphicsContext gc = getCanvas().getGraphicsContext2D();
		gc.setFill(Color.ALICEBLUE);
		gc.fillRect(getX()-3, getY() - 3, 6, 6);
	}
	
}
